package org.jeecg.modules.device.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhouwr.common.enums.ReportMode;
import com.zhouwr.common.exception.IotDeviceDataNodeException;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.modules.alarm.entity.AlarmRecord;
import com.zhouwr.common.enums.AlarmLevel;
import org.jeecg.modules.alarm.service.IAlarmRecordService;
import org.jeecg.modules.device.entity.DataReport;
import org.jeecg.modules.device.entity.DeviceData;
import org.jeecg.modules.device.mapper.DataReportMapper;
import org.jeecg.modules.device.mapper.DeviceDataMapper;
import org.jeecg.modules.device.service.IDataReportService;
import org.jeecg.modules.device.vo.DataReportCountVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Description: 设备上传数据
 * @Author: jeecg-boot
 * @Date: 2020-05-14
 * @Version: V1.0
 */
@Slf4j
@Service
public class DataReportServiceImpl extends ServiceImpl<DataReportMapper, DataReport> implements IDataReportService {
    @Autowired
    private DeviceDataMapper deviceDataMapper;
    @Autowired
    private DataReportMapper reportMapper;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private IAlarmRecordService alarmRecordService;

    @Override
    public String saveData(String instanceId, Map<String, Object> data, ReportMode reportMode) {
        DataReport dataReport = new DataReport();
        dataReport.setCreateTime(new Date());
        dataReport.setData(JSONObject.toJSONString(data));
        dataReport.setReportMode(reportMode);
        dataReport.setInstanceId(instanceId);
        this.save(dataReport);
        return dataReport.getId();
    }

    @Cacheable(value = CacheConstant.CACHE_DEVICE_INSTANCE_DATA_NODES, key = "#deviceInstanceId")
    public Map<String, DeviceData> listDeviceData(String deviceInstanceId) {
        log.info("设备实例数据节点，无缓存调用。。。");
        return deviceDataMapper.selectByInstanceId(deviceInstanceId)
                .stream()
                .collect(Collectors.toMap(DeviceData::getCode, t -> t));
    }

    @Override
    public JSONObject verifyBuildDataNode(String deviceInstanceId, Map<String, Object> dataMap) {
        Set<String> codeSet = (Set<String>) redisTemplate.opsForValue().get(CacheConstant.CACHE_DEVICE_INSTANCE_DATA_NODES + ":" + deviceInstanceId);
        if (codeSet == null) {
            codeSet = deviceDataMapper.selectByInstanceId(deviceInstanceId)
                    .stream()
                    .map(DeviceData::getCode)
                    .collect(Collectors.toSet());
            log.info("无缓存：{}-{}, {}", CacheConstant.CACHE_DEVICE_INSTANCE_DATA_NODES, deviceInstanceId, codeSet);
            redisTemplate.opsForValue().set(CacheConstant.CACHE_DEVICE_INSTANCE_DATA_NODES + ":" + deviceInstanceId, codeSet);
        }
        JSONObject json = new JSONObject();
        Set<String> finalCodeSet = codeSet;
        final Map<String, Object> collect = dataMap.keySet().stream().map(key -> {
            // 校验数据节点
            if (finalCodeSet.contains(key)) {
                return key;
            } else {
                throw new IotDeviceDataNodeException(deviceInstanceId, "数据节点找不到！");
            }
        }).collect(Collectors.toMap(String::valueOf, dataMap::get));
        json.putAll(collect);
        return json;
    }

    @Override
    public DataReport getReportDataLast(String instanceId, String dataCode) {
        final List<DataReport> list = this.lambdaQuery()
                .eq(DataReport::getInstanceId, instanceId)
                .like(DataReport::getData, dataCode)
                .orderByDesc(DataReport::getCreateTime)
                .list();
        if (list != null && list.size() > 0) {
            return list.get(0);
        }
        return new DataReport();
    }

    @Override
    public List<DataReportCountVo> getReportDataCount(String sceneId) {

        return this.reportMapper.countDataBySceneId(sceneId);
    }

    @Override
    public List<DataReportCountVo> getReportDataCount(String sceneId, String sceneSchemeIs) {
        return this.reportMapper.countDataBySceneId(sceneId);
    }

    @Override
    public void reportExtents(IPage<DataReport> pageList) {

        pageList.getRecords().forEach(dataReport -> {
            JSONArray dataArray = new JSONArray();
            String instanceId1 = dataReport.getInstanceId();
            JSONObject.parseObject(dataReport.getData()).forEach((key, value) -> {
                log.info("{} = {}", key, value);
                JSONObject dataJson = new JSONObject();
                // 根据设备实例id，获取设备的数据节点
                List<DeviceData> deviceDataList = deviceDataMapper.select(instanceId1, key);
                if (deviceDataList != null && deviceDataList.size() == 1) {
                    DeviceData deviceData = deviceDataList.get(0);
                    // 数据名称，数据值
                    dataJson.put("name", deviceData.getName());
                    dataJson.put("code", deviceData.getCode());
                    dataJson.put("value", value);
                    // 数据告警
                    List<AlarmRecord> alarmRecords = alarmRecordService.lambdaQuery().eq(AlarmRecord::getReportDataId, dataReport.getId()).list();
                    if (alarmRecords != null && alarmRecords.size() == 1) {
                        AlarmRecord alarmRecord = alarmRecords.get(0);
                        dataJson.put("alarmLevel", alarmRecord.getAlarmLevel());
                    } else {
                        dataJson.put("alarmLevel", AlarmLevel.NORMAL);
                    }
                }
                dataArray.add(dataJson);
            });
            dataReport.setDataMap(dataArray);
        });
    }
}
